home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 1.iso
/
ARGONET
/
PD
/
GAMES
/
WIMPGAME
/
MINES2.ZIP
/
!Mines
/
c
/
Hint
< prev
next >
Wrap
Text File
|
1995-05-03
|
25KB
|
785 lines
#include "MineHeader.h"
#include "Mines.h"
#include "Mouse.h"
#define in_playground(x,y) (((x)>=0) && ((x)<XMAX) && ((y)>=0) && ((y)<YMAX))
int move_wrong(int x0,int y0)
{
return ((feld[x0][y0] & MARK) && !(feld[x0][y0] & MINE));
}
int move_obvious(int x0,int y0)
{
/* ein Zug ist offensichtlich, wenn die Anzahl der Nachbarfelder
** gleich der Anzahl der Nachbarminen ist ( dann bekommt jedes
** Nachbarfeld eine Marke ), oder wenn die Anzahl der Nachbarminen
** gleich der Anzahl der Nachbarmarken ist ( dann sind alle ver-
** deckten Felder leer.
*/
int mines=0,marks=0,unknown=0,d;
if (feld[x0][y0] & CLOSED) return(FALSE);
for (d=0;d<8;d++)
{
int x1=x0+off[d][0],y1=y0+off[d][1];
if (in_playground(x1,y1))
{
register char f=feld[x1][y1];
if (f & CLOSED) {if (f & MARK) marks++; else unknown++;};
if (f & MINE) mines++;
}
}
if ((unknown!=0) && ((marks==mines) || (marks+unknown==mines))) return(TRUE);
return(FALSE);
}
/* Variablen fuer den Algorithmus */
typedef struct {char x,y,domain;int test;} border_typ;
border_typ *border_arr,*border_anz,*last_border_arr=0,*last_border_anz;
int *minmax,*lastminmax,unnecessary_hints;
/* Makros fuer den Zugriff auf minmax und lastminmax
** (ich weiss nicht, wie man Zeiger auf mehrdimensionale Felder
** vereinbart, so dass es kein Feld von Zeigern ist).
** int *minmax[3]; ?
*/
#define min(domain) minmax[(domain)*2]
#define max(domain) minmax[(domain)*2+1]
#define last_min(last_domain) lastminmax[(last_domain)*2]
#define last_max(last_domain) lastminmax[(last_domain)*2+1]
/* Variablen fuer die WIMP-Unterstuetzung */
window_data hint_window,hint_choose_window;
char clue_msg1[]=" You can still make some clues ! ";
char clue_msg2[]=" Give one ? ";
char hint_msg1[]=" You don't need a hint ! ";
char hint_msg2[]=" Give anyway ? ";
char err_msg1[] =" You made a mistake ! ";
char err_msg2[] =" Show it ? ";
int hint_index,hint_choose=FALSE;
int find_next(int *x,int *y)
{
/*
** sucht das naechste Feld, dass sowohl bedeckte als auch unbedeckte
** Felder als Nachbarn hat und selbst bedeckt ist, aber keine Marke
** hat, kurz gesagt: am Rand ist.
*/
int closed_neighbors,open_neighbors,d;
do {
open_neighbors=0;closed_neighbors=0;
*x+=1;if (*x>=XMAX) {*x=0;*y+=1;};
if (*y<YMAX)
for (d=0;d<8;d++)
{
int newx=*x+off[d][0],newy=*y+off[d][1];
if (in_playground(newx,newy))
{if (feld[newx][newy] & CLOSED) closed_neighbors++;
else open_neighbors++;};
}
} while ((*y<YMAX) && ((feld[*x][*y] & MARK) || !(feld[*x][*y] & CLOSED) || (open_neighbors==0) || (closed_neighbors==0)));
if (*y>=YMAX) return FALSE;
return TRUE;
}
/* ===============================================================
** = Routinen zur Sortierung in Bereiche =
** ===============================================================
*/
border_typ *find_field(int x,int y,border_typ *i)
{
/* sucht ein Feld mit Koordinaten (x/y) in border_arr
** ab Position i. Gibt eine Pointer auf das passende
** Element zurueck, sonst 0.
*/
while ((i<border_anz) && ((i->x!=x) || (i->y!=y))) i++;
if ((x==i->x) && (y==i->y) && (i<border_anz)) return i;
return 0;
}
border_typ *exchange_field(border_typ *end_domain,border_typ *i,char domain)
{
/* sortiert den Inhalt von i an das Ende des Bereiches,
** vergroessert den Bereich um eins und gibt den neuen
** Zeiger auf das Ende des Bereiches zurueck.
*/
border_typ d;
if (i==0) return end_domain;
end_domain++;
d=*end_domain;*end_domain=*i;*i=d;
end_domain->domain=domain;
return end_domain;
}
border_typ *find_neighbors(int x0,int y0,border_typ *end_domain,char domain)
{
/* sortiert alle Nachbarn des Feldes (x0/y0) an des Ende des
** Bereiches und gibt den neuen Zeiger auf das Bereichsende
** zurueck.
*/
char d;
for (d=0;d<8;d++)
end_domain=exchange_field(end_domain,
find_field(x0+off[d][0],y0+off[d][1],end_domain+1),
domain);
return end_domain;
}
border_typ *find_domains(border_typ *border,char domain)
{
/* Sortiert alle zusammengehoerigen Felder ab border
** in einen Bereich mit der Nummer domain. Dazu werden
** alle Nachbarfelder offener Nachbarfelder zusammengesucht.
*/
char d;
border_typ *end_domain=border;
border->domain=domain;
do {
for (d=0;d<8;d++)
{
int x=border->x+off[d][0],y=border->y+off[d][1];
if (in_playground(x,y) && !(feld[x][y] & CLOSED))
end_domain=find_neighbors(x,y,end_domain,domain);
}
border++;
} while ((border->domain==domain) && (border<border_anz));
return end_domain+1;
}
/* ========================================================
** = Routine zur Optimierung des Abbruchtestes =
** ========================================================
*/
#define F0 0X00000001
#define F1 0X00000010
#define F2 0X00000100
#define F3 0X00001000
#define F4 0X00010000
#define F5 0X00100000
#define F6 0X01000000
#define F7 0X10000000
void find_testmode(border_typ *border,char domain)
{
/* versieht jedes Feld mit einer Maske, die fuer jede Richtung
** ein Bit enthaelt, das anzeigt, ob ein offenes Nachbarfeld
** in dieser Richtung genau verglichen werden kann oder nicht.
** Es kann genau verglichen werden, wenn keines seiner Nachbar-
** felder mehr veraendert werden kann, d.h. sich kein Nachbar-
** feld spaeter in dem Bereich befindet.
*/
os_error fielddouble = { 0 , "Field Double"} ;
while ((border->domain==domain) && (border<border_anz))
{
border_typ *ptr=border+1;
char x,y;
x=border->x;y=border->y;border->test=0;
while ((ptr->domain==domain) && (ptr<border_anz))
{
char x1=ptr->x,y1=ptr->y;
if (y1+2==y)
{
if (x1+2==x) border->test+=F0;
if (x1+1==x) border->test+=F0+F1;
if (x1==x) border->test+=F0+F1+F2;
if (x1==x+1) border->test+=F1+F2;
if (x1==x+2) border->test+=F2;
}
if (y1+1==y)
{
if (x1+2==x) border->test+=F0+F3;
if (x1+1==x) border->test+=F0+F1+F3;
if (x1==x) border->test+=F0+F1+F2+F3+F4;
if (x1==x+1) border->test+=F1+F2+F4;
if (x1==x+2) border->test+=F2+F4;
}
if (y1==y)
{
if (x1+2==x) border->test+=F0+F3+F5;
if (x1+1==x) border->test+=F0+F1+F3+F5+F6;
if (x1==x) wimp_report_error(&fielddouble,2,"Mines !");
if (x1==x+1) border->test+=F1+F2+F4+F6+F7;
if (x1==x+2) border->test+=F2+F4+F7;
}
if (y1==y+1)
{
if (x1+2==x) border->test+=F3+F5;
if (x1+1==x) border->test+=F3+F5+F6;
if (x1==x) border->test+=F3+F4+F5+F6+F7;
if (x1==x+1) border->test+=F4+F6+F7;
if (x1==x+2) border->test+=F4+F7;
}
if (y1==y+2)
{
if (x1+2==x) border->test+=F5;
if (x1+1==x) border->test+=F5+F6;
if (x1==x) border->test+=F5+F6+F7;
if (x1==x+1) border->test+=F6+F7;
if (x1==x+2) border->test+=F7;
}
ptr++;
} /* while (ptr->domain==domain) */
border++;
} /* while (border->domain==domain) */
}
/* ==========================================================
** = Routinen zum Vergleich mit schon berechneten Bereichen =
** ==========================================================
*/
char find_last_domain(border_typ *start,border_typ *border)
{
/* sucht den Bereich, in dem sich (border->x/border->y)
** das letzte Mal befunden hat. Gibt es keinen, wird
** 0 zurueckgegeben, ansonsten die Nummer des Bereiches.
*/
border_typ *ptr=start;
while ((ptr<last_border_anz) &&
((border->x!=ptr->x) || (border->y!=ptr->y)))
ptr++;
if (ptr>=last_border_anz) return 0;
return ptr->domain;
}
char find_new_domain(border_typ *start,border_typ *last_border)
{
/* sucht den Bereich, in dem sich (last_border->x/last_border->y)
** diesmal befindet und gibt seine Nummer zurueck. Gibt es ihn
** nicht, eine 0.
*/
border_typ *ptr=start;
while ((ptr<border_anz) &&
((last_border->x!=ptr->x) || (last_border->y!=ptr->y)))
ptr++;
if (ptr>=border_anz) return 0;
return ptr->domain;
}
char look_for_old_domain(border_typ *border,char domain)
{
/* sucht, ob sich der Bereich domain auch in last_border_arr
** befindet. Dazu muessen alle Felder in domain auch in der
** gleichen last_domain liegen, und alle Felder dieser
** last_domain in domain. Ist dem so, wird die last_domain
** zurueckgegeben, sonst 0.
** Es kann nicht davon ausgegangen werden, dass die Felder in
** beiden Bereichen in der gleichen Reihenfolge liegen, was
** den Vergleich etwas kompliziert.
*/
border_typ *ptr=border,*start_of_last_domain;
char last_domain;
if (last_border_anz-last_border_arr==0) return 0;
if ((last_domain=find_last_domain(last_border_arr,ptr))==0) return 0;
start_of_last_domain=last_border_arr;
while (start_of_last_domain->domain!=last_domain)
start_of_last_domain++;
do { ptr++;
} while ((ptr<border_anz) && (ptr->domain==domain) &&
(last_domain==find_last_domain(start_of_last_domain,ptr)));
if ((ptr<border_anz) && (ptr->domain==domain)) return 0;
ptr=last_border_arr;
while ((ptr->domain!=last_domain) && (ptr<last_border_anz)) ptr++;
if (ptr>=last_border_anz) return 0;
while ((ptr<last_border_anz) && (ptr->domain==last_domain) &&
(domain==find_new_domain(border,ptr)))
ptr++;
if ((ptr<last_border_anz) && (ptr->domain==last_domain)) return 0;
return last_domain;
}
void init_border()
{
border_typ *border;
int x,y;
char domain,last_domain;
border_anz=border_arr;x=-1;y=0;
while (find_next(&x,&y)) /* create border list */
{
border_anz->x=x;border_anz->y=y;border_anz->domain=0;
border_anz++;
}
if (border_anz==border_arr) return;
domain=0;border=border_arr; /* sort border_arr in Bereiche */
do {
domain++;
if (domain==CHAR_MAX)
{ /* this will never occur, but I can cope with it ;-> */
border_typ *ptr=border;
while (ptr<border_anz) {border->domain=domain;ptr++;}
} else find_domains(border,domain);
if ((last_domain=look_for_old_domain(border,domain))==0)
{ /* Bereich ist neu */
min(domain)=INT_MAX;max(domain)=INT_MIN;
} else
{ /* Bereich war schon mal da */
min(domain)=last_min(last_domain);
max(domain)=last_max(last_domain);
}
find_testmode(border,domain);
while ((border->domain==domain) && (border<border_anz)) border++;
} while (border<border_anz);
}
void exit_border()
{
/* Speichert die erhaltenen Ergebnisse in last_border_arr
** bzw in lastminmax ab.
*/
border_typ *b=last_border_arr;int *i=lastminmax;
last_border_arr=border_arr;border_arr=b;last_border_anz=border_anz;
lastminmax=minmax;minmax=i;
}
/* Konstanten fuer die Speicherung der Belegungen */
#define h_MASK 192
#define h_EVERYTHING 0
#define h_NOMINE 64
#define h_MINE 128
#define h_UNKNOWN 192
int otest_if_possible(border_typ *border_ptr)
{
/* Testet, ob die Wahl dieses Feldes gegen Informationen
** der Nachbarfelder verstoesst.
** Diese Funktion wurde aus Geschwindigkeitsgruenden
** vollsaendig in Assembler umgesetzt. Der C-Code dient
** nur noch der Illustration der Arbeitsweise.
*/
char d0,d1,mines,marks,x1,y1;
for (d0=0;d0<8;d0++)
{
x1=border_ptr->x+off[d0][0];
y1=border_ptr->y+off[d0][1];
if (in_playground(x1,y1) && !(feld[x1][y1] & CLOSED))
{
mines=0;marks=0;
for (d1=0;d1<8;d1++)
{
char x2=x1+off[d1][0],y2=y1+off[d1][1];
if (in_playground(x2,y2))
{
register char f=feld[x2][y2];
if (f & MINE) mines++;
if (f & MARK) marks++;
}
}
if (marks>mines) return FALSE;
if (marks+((border_ptr->test >> d0*4) & 0xF)<mines) return FALSE;
/*if ((border_ptr->test & (1 << d0))!=0)
{ if (marks>mines) return FALSE; }
else { if (marks!=mines) return FALSE; }*/
}
}
return(TRUE);
}
/* die Asseblerversion von test_if_possible
** Bei Bedarf kann das Makro in
** #define ctest_if_possible(b) otest_if_possible(b)
** geaendert werden. Dann wird wieder die C-Routine benutzt.
*/
#include "HintA.h"
#define ctest_if_possible(b) test_if_possible(b,XMAX,YMAX,feld)
/*#define ctest_if_possible(b) otest_if_possible(b)*/
/* Rueckgabewerte der Rekursionsroutinen */
#define p_POSSIBLE TRUE
#define p_IMPOSSIBLE FALSE
char permutate1(border_typ *border,int mine_anz,char domain)
{
/* Rekursion mit Abspeichernung der Minimal- und
** Maximalwerte, ohne Markenbegrenzung.
*/
char x,y;
char p1=p_IMPOSSIBLE,p2=p_IMPOSSIBLE,f1,f2;
if ((border->domain!=domain) || (border>=border_anz))
{
if (mine_anz>max(domain)) max(domain)=mine_anz;
if (mine_anz<min(domain)) min(domain)=mine_anz;
return p_POSSIBLE;
}
x=border->x;y=border->y;
if (ctest_if_possible(border)) p1=permutate1(border+1,mine_anz,domain);
feld[x][y]|=MARK;
if (ctest_if_possible(border)) p2=permutate1(border+1,mine_anz+1,domain);
feld[x][y]&=~MARK;
f1=feld[x][y] & h_MASK;f2=feld[x][y] & ~h_MASK;
if (p1==p_POSSIBLE)
{
if ((f1==h_NOMINE) || (f1==h_EVERYTHING)) f1=h_NOMINE;
else f1=h_UNKNOWN;
}
if (p2==p_POSSIBLE)
{
if ((f1==h_MINE) || (f1==h_EVERYTHING)) f1=h_MINE;
else f1=h_UNKNOWN;
}
feld[x][y]=f2 | f1;
return(p1 | p2);
}
char permutate0(border_typ *border,int mine_anz,char domain,char percent,char inc)
{
/* Rekursion mit Abspeichernung der Minimal- und
** Maximalwerte, ohne Markenbegrenzung und als
** besonderes Schmankerl fuer den ungeduldigen
** Spieler mit Prozentanzeige bei der Sanduhr.
*/
char x,y;
char p1=p_IMPOSSIBLE,p2=p_IMPOSSIBLE,f1,f2;
if ((border->domain!=domain) || (border>=border_anz))
{
if (mine_anz>max(domain)) max(domain)=mine_anz;
if (mine_anz<min(domain)) min(domain)=mine_anz;
return p_POSSIBLE;
}
x=border->x;y=border->y;
hourglass_percentage(percent);
if (ctest_if_possible(border))
{
if (inc<10) p1=permutate1(border+1,mine_anz,domain);
else p1=permutate0(border+1,mine_anz,domain,percent,inc/2);
}
hourglass_percentage(percent+inc);
feld[x][y]|=MARK;
if (ctest_if_possible(border))
{
if (inc<10) p2=permutate1(border+1,mine_anz+1,domain);
else p2=permutate0(border+1,mine_anz+1,domain,percent+inc,inc/2);
}
feld[x][y]&=~MARK;
f1=feld[x][y] & h_MASK;f2=feld[x][y] & ~h_MASK;
if (p1==p_POSSIBLE)
{
if ((f1==h_NOMINE) || (f1==h_EVERYTHING)) f1=h_NOMINE;
else f1=h_UNKNOWN;
}
if (p2==p_POSSIBLE)
{
if ((f1==h_MINE) || (f1==h_EVERYTHING)) f1=h_MINE;
else f1=h_UNKNOWN;
}
feld[x][y]=f2 | f1;
return(p1 | p2);
}
char permutate2(border_typ *border,int mine_anz)
{
/* Rekursion mit Markenbegrenzung, ohne Feststellung
** der Minimal- und Maximalwerte und ohne Prozentausgabe.
** Die Rekursion laeuft ueber das ganze border_arr, das
** aber gegen Spielende, wenn diese Rekursion benutzt ist,
** hoffentlich so klein ist, dass es keine merkliche
** Rechenzeit beansprucht.
*/
char x,y;
char p1=p_IMPOSSIBLE,p2=p_IMPOSSIBLE,f1,f2;
if (border>=border_anz)
{
if (mines_left+fields_left-(border_anz-border_arr)>=mine_anz)
return p_POSSIBLE; else return p_IMPOSSIBLE;
}
x=border->x;y=border->y;
if (ctest_if_possible(border))
p1=permutate2(border+1,mine_anz);
if (mine_anz>0)
{
feld[x][y]|=MARK;
if (ctest_if_possible(border)) p2=permutate2(border+1,mine_anz-1);
feld[x][y]&=~MARK;
}
f1=feld[x][y] & h_MASK;f2=feld[x][y] & ~h_MASK;
if (p1==p_POSSIBLE)
{
if ((f1==h_NOMINE) || (f1==h_EVERYTHING)) f1=h_NOMINE;
else f1=h_UNKNOWN;
}
if (p2==p_POSSIBLE)
{
if ((f1==h_MINE) || (f1==h_EVERYTHING)) f1=h_MINE;
else f1=h_UNKNOWN;
}
feld[x][y]=f2 | f1;
return(p1 | p2);
}
/* ein Hinweis */
void hint_it(void)
{
char x,y,p=0,domain;
int closed_fields_without_border,max_mines,min_mines;
border_typ *border,*ptr;
os_error nrf={0,"negative rest fields !"};
/* Suche nach einem falschen Zug */
border_anz=border_arr;
for (x=0;x<XMAX;x++)
for (y=0;y<YMAX;y++)
if (move_wrong(x,y))
{border_anz->x=x;border_anz->y=y;border_anz++;};
if (border_anz!=border_arr)
{
wimp_window_state w;
wimp_icon *i=hint_window.window->icons;
strcpy(i[0].data.indirected_text.text,err_msg1);
strcpy(i[1].data.indirected_text.text,err_msg2);
hint_index=2;
w.w = hint_window.w ;
wimp_get_window_state(&w);
set_mouse_box(&w.visible);
w.next=wimp_TOP;
wimp_open_window((wimp_open *)&w);
return;
}
/* Suche nach einem offensichtlichen Zug */
border_anz=border_arr;
for (x=0;x<XMAX;x++)
for (y=0;y<YMAX;y++)
if (move_obvious(x,y))
{border_anz->x=x;border_anz->y=y;border_anz++;};
if (border_anz!=border_arr)
{
wimp_window_state w;
wimp_icon *i=hint_window.window->icons;
strcpy(i[0].data.indirected_text.text,hint_msg1);
strcpy(i[1].data.indirected_text.text,hint_msg2);
hint_index=1;
w.w = hint_window.w ;
wimp_get_window_state(&w);
set_mouse_box(&w.visible);
w.next=wimp_TOP;
wimp_open_window((wimp_open *)&w);
return;
}
/* Suche nach einer eindeutigen Schlussfolgerung */
init_border();
if (border_anz==border_arr)
{ /* Wenn es keinen Rand gibt, kriegt er einen Tip */
wimp_window_state s;
ptr=border_arr;
for (x=0;x<XMAX;x++) for (y=0;y<YMAX;y++)
if ((feld[x][y] & CLOSED) && !(feld[x][y] & MARK)) {ptr->x=x;ptr->y=y;ptr++;}
border_anz=ptr;
hint_choose=TRUE;
s.w = hint_choose_window.w ;
wimp_get_window_state(&s);
s.next=wimp_TOP;
wimp_open_window((wimp_open *)&s);
return;
}
border=border_arr;domain=1;max_mines=0;min_mines=0;
hourglass_on();
do {
if (max(domain)==INT_MIN)
{
for (ptr=border;ptr->domain==domain;ptr++)
feld[ptr->x][ptr->y]&=~h_MASK;
permutate0(border,0,domain,0,50);
}
max_mines+=max(domain);min_mines+=min(domain);
while ((border->domain==domain) && (border<border_anz)) border++;
domain++;
} while (border<border_anz);
hourglass_off();
closed_fields_without_border=mines_left+fields_left - (border_anz-border_arr);
if (closed_fields_without_border<0) wimp_report_error(&nrf,2,"Mines !");
if ((max_mines>mines_left) ||
(closed_fields_without_border<mines_left-min_mines))
{
for (ptr=border_arr;ptr<border_anz;ptr++)
feld[ptr->x][ptr->y]&=~h_MASK;
permutate2(border_arr,mines_left);
if (max_mines>mines_left) max_mines=mines_left;
}
if ((closed_fields_without_border>0) &&
((min_mines==mines_left) ||
(closed_fields_without_border==mines_left-max_mines)))
{
wimp_window_state s;
wimp_icon *i=hint_window.window->icons;
strcpy(i[0].data.indirected_text.text,hint_msg1);
strcpy(i[1].data.indirected_text.text,hint_msg2);
hint_index=3;
s.w = hint_window.w ;
wimp_get_window_state(&s);
set_mouse_box(&s.visible);
s.next=wimp_TOP;
wimp_open_window((wimp_open *)&s);
return;
}
for (border=border_arr;border<border_anz;border++)
{
register unsigned char d=feld[border->x][border->y] & h_MASK;
if ((d==h_NOMINE) || (d==h_MINE)) p++;
}
if (p!=0)
{
wimp_window_state s;
wimp_icon *i=hint_window.window->icons;
strcpy(i[0].data.indirected_text.text,clue_msg1);
strcpy(i[1].data.indirected_text.text,clue_msg2);
hint_index=0;
s.w = hint_window.w ;
wimp_get_window_state(&s);
set_mouse_box(&s.visible);
s.next=wimp_TOP;
wimp_open_window((wimp_open *)&s);
return;
}
{
wimp_window_state s;
hint_choose=TRUE;
s.w = hint_choose_window.w;
wimp_get_window_state(&s);
s.next=wimp_TOP;
wimp_open_window((wimp_open *)&s);
}
}
void give_hint(void)
{
char d,x,y;
border_typ border=border_arr[rand() % (border_anz-border_arr)];
for (d=0;d<8;d++)
{
x=border.x+off[d][0];y=border.y+off[d][1];
if ((x>=0) && (x<XMAX) && (y>=0) && (y<YMAX) &&
(feld[x][y] & CLOSED) && !(feld[x][y] & MARK))
draw_sprite(x,y,questionmark.id);
}
}
void give_no_hint(void)
{
}
void give_clue(void)
{
char f;
border_typ *border;
do {
border=&border_arr[rand() % (border_anz-border_arr)];
f=feld[border->x][border->y] & h_MASK;
} while ((f!=h_NOMINE) && (f!=h_MINE));
draw_sprite(border->x,border->y,questionmark.id);
exit_border();
}
void give_no_clue(void)
{
exit_border();
}
void give_err(void)
{
border_typ border=border_arr[rand() % (border_anz-border_arr)];
draw_sprite(border.x,border.y,nomine.id);
}
void give_no_err(void)
{
}
void give_count(void)
{
int x,y,d,c;
border_anz=border_arr;
for (x=0;x<XMAX;x++) for (y=0;y<YMAX;y++)
{
c=0;for (d=0;d<8;d++)
if ((in_playground(x+off[d][0],y+off[d][1])) &&
(!(feld[x+off[d][0]][y+off[d][1]] & CLOSED))) c++;
if (c==0) {border_anz->x=x;border_anz->y=y;border_anz++;}
}
border_anz=&border_arr[rand() % (border_anz-border_arr)];
draw_sprite(border_anz->x,border_anz->y,questionmark.id);
}
void give_no_count(void)
{
}
void hint_click(wimp_block *b)
{if(b->pointer.w == hint_window.w)
{if (b->pointer.i==2)
{switch (hint_index)
{case 0 : give_clue();break;
case 1 : give_hint();break;
case 2 : give_err();break;
case 3 : give_count();break;
}
unnecessary_hints+=1;
wimp_close_window(hint_window.w);
set_mouse_box_screen();
}
if((b->pointer.i==3) || (b->pointer.buttons & 2))
{switch (hint_index)
{case 0 : give_no_clue();break;
case 1 : give_no_hint();break;
case 2 : give_no_err();break;
case 3 : give_no_count();break;
}
unnecessary_hints+=1;
wimp_close_window(hint_window.w);
set_mouse_box_screen();
}
}
}
void hint_choose_handler(int event,wimp_block *b,void *handle)
{
switch (event)
{
case wimp_OPEN_WINDOW_REQUEST:
wimp_open_window(&(b->open));
break;
default : break;
}
}
int hint_choose_done(int x, int y,bits *button)
{
border_typ *ptr=border_arr;
if (!hint_choose) return FALSE;
while (((ptr->x!=x) || (ptr->y!=y)) && (ptr<border_anz)) ptr++;
if (ptr>=border_anz) {*button=0;return FALSE;}
wimp_close_window(hint_choose_window.w);
if (feld[x][y] & MINE) *button=wimp_CLICK_ADJUST; else *button=wimp_CLICK_SELECT;
hint_choose=FALSE;
exit_border();
return TRUE;
}
int hint_init(void)
{loadwin(&hint_window,"Hint");
werr(xwimp_create_window(hint_window.window,&hint_window.w)) ;
loadwin(&hint_choose_window,"Hintchoose");
werr(xwimp_create_window(hint_choose_window.window,&hint_choose_window.w)) ;
if ((border_arr=border_anz=malloc(XMAX*YMAX*sizeof(border_typ)))==0)
return FALSE;
if ((last_border_arr=last_border_anz=malloc(XMAX*YMAX*sizeof(border_typ)))==0)
return FALSE;
if ((minmax=malloc(512*sizeof(int)))==0) return FALSE;
if ((lastminmax=malloc(512*sizeof(int)))==0) return FALSE;
return TRUE;
}
void hint_new_game(void)
{
unnecessary_hints=0;
if (hint_choose) wimp_close_window(hint_choose_window.w);
hint_choose=FALSE;
}
void hint_exit(void)
{
free(border_anz);
free(last_border_anz);
free(minmax);
free(lastminmax);
}